package com.docker.core.mvc.dao;

import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;

import java.util.List;
import java.util.Map;

/**
 * 数据持久化操作封装(基于JFinal  DB + Record + Enjoy)
 * 方法命名规则： [前缀] + 功能方法名
 * 方法名 | 对应功能 | sql指令
 * -----------------------------
 * save      新增     insert
 * update    修改     update
 * delete    删除     delete
 * list      列表     select
 * paginate  分页     select
 * info/row  单行     select
 * <p>
 * 前缀说明：
 * tpl    基于SQL模板，且参数为 ? 占位符
 * tplSP  基于SQL模板，且参数为 SqlPara
 * <p>
 * 继承说明：
 * 子类需实现 getDbName() 方法用于指定数据源名称
 * 子类需实现 getSqlTplNameSpace() 方法用于查找SQL模板命名空间
 */
public abstract class BaseModelDao {

    /**
     * 获取数据源名称
     */
    protected abstract String getDbName();

    /**
     * 获取SQL模板命名空间
     */
    protected abstract String getSqlTplNameSpace();

    private String buildSqlKey(String sqlKey) {
        return getSqlTplNameSpace() + "." + sqlKey;
    }

    // =========================== 无前缀系列方法 =======================

    /**
     * 新增、增加
     *
     * @param tableName  表名
     * @param primaryKey 主键
     * @param record     封装数据Record对象
     */
    protected boolean save(String tableName, String primaryKey, Record record) {
        return Db.use(getDbName()).save(tableName, primaryKey, record);
    }

    /**
     * 修改、更新
     *
     * @param tableName  表名
     * @param primaryKey 主键
     * @param record     封装数据Record对象
     * @return boolean 修改是否成功
     */
    protected boolean update(String tableName, String primaryKey, Record record) {
        return Db.use(getDbName()).update(tableName, primaryKey, record);
    }

    /**
     * 删除
     *
     * @param tableName  表名
     * @param primaryKey 主键
     * @param ids        ID
     * @return boolean 删除是否成功
     */
    protected boolean delete(String tableName, String primaryKey, Object... ids) {
        return Db.use(getDbName()).deleteById(tableName, primaryKey, ids);
    }

    protected boolean deleteById(String tableName, String primaryKey, Object idValue) {
        return Db.use(getDbName()).deleteById(tableName, primaryKey, idValue);
    }

    protected boolean deleteByRecord(String tableName, String primaryKey, Record record) {
        return Db.use(getDbName()).delete(tableName, primaryKey, record);
    }

    protected int tplDelete(String sqlKey, Object... paras) {
        return Db.use(getDbName()).delete(Db.use(getDbName()).getSql(buildSqlKey(sqlKey)), paras);
    }

    /**
     * 批量新增
     *
     * @param tableName 表名
     * @param list      封装数据Record对象列表
     * @return int[] 新增成功条数
     */
    protected int[] batchSave(String tableName, List<Record> list) {
        return Db.use(getDbName()).batchSave(tableName, list, list.size());
    }

    /**
     * 获取单行数据对象
     *
     * @param tableName  表名
     * @param primaryKey 主键
     * @param id         ID
     * @return Record 数据对象
     */
    protected Record info(String tableName, String primaryKey, Object id) {
        return Db.use(getDbName()).findById(tableName, primaryKey, id);
    }


    // =========================== tpl前缀系列方法 =======================

    /**
     * 新增(基于模板占位符)
     *
     * @param sqlKey SQL模板key
     * @param paras  占位符参数
     * @return int 新增影响行数
     */
    protected int tplSave(String sqlKey, Object... paras) {
        return Db.use(getDbName()).update(Db.use(getDbName()).getSql(buildSqlKey(sqlKey)), paras);
    }


    /**
     * 修改(基于模板占位符)
     *
     * @param sqlKey SQL模板key
     * @param paras  占位符参数
     * @return 更新影响行数
     */
    protected int tplUpdate(String sqlKey, Object... paras) {
        return Db.use(getDbName()).update(Db.use(getDbName()).getSql(buildSqlKey(sqlKey)), paras);
    }

    /**
     * 获取单行数据(基于模板占位符)
     *
     * @param sqlKey SQL模板key
     * @param paras  占位符参数
     * @return Record 数据对象
     */
    protected Record tplInfo(String sqlKey, Object... paras) {
        return Db.use(getDbName()).findFirst(Db.use(getDbName()).getSql(buildSqlKey(sqlKey)), paras);
    }

    /**
     * 获取数据列表(基于模板占位符)
     *
     * @param sqlKey SQL模板key
     * @param paras  占位符参数
     * @return List<Record> 数据列表
     */
    protected List<Record> tplList(String sqlKey, Object... paras) {
        return Db.use(getDbName()).find(Db.use(getDbName()).getSql(buildSqlKey(sqlKey)), paras);
    }

    /**
     * 获取数据分页信息(基于模板占位符)
     *
     * @param sqlKey   SQL模板key
     * @param pageNum  页码
     * @param pageSize 每页条数
     * @param paras    占位符参数
     * @return Page<Record> 分页信息对象
     */
    protected Page<Record> tplPaginate(String sqlKey, int pageNum, int pageSize, Object... paras) {
        return Db.use(getDbName()).paginate(pageNum, pageSize, Db.use(getDbName()).getSqlPara(buildSqlKey(sqlKey), paras));
    }

    /**
     * 获取单个Integer结果列(基于模板占位符)
     *
     * @param sqlKey SQL模板key
     * @param paras  占位符参数
     * @return Integer 数值
     */
    protected Integer tplQueryInt(String sqlKey, Object... paras) {
        return Db.use(getDbName()).queryInt(Db.use(getDbName()).getSql(buildSqlKey(sqlKey)), paras);
    }

    /**
     * 获取单个String结果列(基于模板占位符)
     *
     * @param sqlKey SQL模板key
     * @param paras  占位符参数
     * @return String 字符串
     */
    protected String tplQueryStr(String sqlKey, Object... paras) {
        return Db.use(getDbName()).queryStr(Db.use(getDbName()).getSql(buildSqlKey(sqlKey)), paras);
    }

    /**
     * 获取泛型结果列表(基于模板占位符)
     *
     * @param sqlKey SQL模板key
     * @param paras  占位符参数
     * @param <T>    类型
     * @return <T> List<T>
     */
    protected <T> List<T> tplQuery(String sqlKey, Object... paras) {
        if (paras.length == 0) {
            return Db.use(getDbName()).query(Db.use(getDbName()).getSql(buildSqlKey(sqlKey)));
        }
        return Db.use(getDbName()).query(Db.use(getDbName()).getSql(buildSqlKey(sqlKey)), paras);
    }


    // =========================== tplSP前缀系列方法 =======================

    /**
     * 获取数据列表(基于模板sqlPara)
     *
     * @param sqlKey SQL模板key
     * @param cond   参数键值对
     * @return List<Record> 数据列表
     */
    protected List<Record> tplSPList(String sqlKey, Map cond) {
        if (StrKit.notNull(cond)) {
            return Db.use(getDbName()).find(Db.use(getDbName()).getSqlPara(buildSqlKey(sqlKey), cond));
        }
        return Db.use(getDbName()).find(Db.use(getDbName()).getSqlPara(buildSqlKey(sqlKey)));
    }

    /**
     * 获取数据分页(基于模板sqlPara)
     *
     * @param sqlKey     SQL模板 key
     * @param cond       参数键值对
     * @param pageNumber 页码
     * @param pageSize   每页条数
     * @return Page<Record> 分页对象
     */
    protected Page<Record> tplSPPaginate(String sqlKey, Map cond, int pageNumber, int pageSize) {
        if (StrKit.notNull(cond)) {
            return Db.use(getDbName()).paginate(pageNumber, pageSize, Db.use(getDbName()).getSqlPara(buildSqlKey(sqlKey), cond));
        }
        return Db.use(getDbName()).paginate(pageNumber, pageSize, Db.use(getDbName()).getSqlPara(buildSqlKey(sqlKey)));
    }

    /**
     * 获取单行数据(基于模板sqlPara)
     *
     * @param sqlKey SQL模板 key
     * @param cond   参数键值对
     * @return Record 数据对象
     */
    protected Record tplSPInfo(String sqlKey, Map cond) {
        if (StrKit.notNull(cond)) {
            return Db.use(getDbName()).findFirst(Db.use(getDbName()).getSqlPara(buildSqlKey(sqlKey), cond));
        }
        return Db.use(getDbName()).findFirst(Db.use(getDbName()).getSqlPara(buildSqlKey(sqlKey)));
    }

}
